﻿@namespace AntDesign
@inherits AntDomComponentBase
@using AntDesign.TableModels
@using AntDesign.Internal
@using AntDesign.Core.Component.ResizeObserver

@typeparam TItem

<div class="@_wrapperClassMapper.Class" @ref="Ref">
    <Spin Spinning="Loading">
        @if (!HidePagination && PaginationPosition.Contains("top"))
        {
            if (PaginationTemplate == null)
            {
                <Pagination Size="@(Size == TableSize.Default ? PaginationSize.Default : PaginationSize.Small)"
                            Class="@_paginationClass.Class"
                            Total="_total"
                            PageSize="PageSize"
                            Current="PageIndex"
                            OnChange="HandlePageChange" />
            }
            else
            {
                @PaginationTemplate((PageSize,PageIndex,_total,_paginationClass.Class, EventCallback.Factory.Create<PaginationEventArgs>(this, HandlePageChange)))
            }
        }

        <CascadingValue Value="@this" TValue="ITable" IsFixed>
            <CascadingValue Value=@typeof(TItem) Name="ItemType" IsFixed>
                <CascadingValue Value="@ColumnContext" IsFixed>
                    <CascadingValue Name="IsInitialize" Value="true" IsFixed>
                        @ChildContent(_fieldModel)
                    </CascadingValue>
                    <div class="@ClassMapper.Class">
                        @if (TitleTemplate != null || Title != null)
                        {
                            <div class="ant-table-title">
                                @if (TitleTemplate != null)@TitleTemplate else @Title
                            </div>
                        }
                        <div class="ant-table-container">
                            @if (ScrollY != null)
                            {
                                <div class="ant-table-header" style="overflow: hidden;" @ref="_tableHeaderRef">
                                    <table style="@TableLayoutStyle">
                                        @colGroup((this, true))
                                        @header(this)
                                    </table>
                                </div>
                                <div class="ant-table-body" @ref="_tableBodyRef" style="@(ScrollX!=null?" overflow: auto scroll;":"overflow-y: scroll;") max-height: @((CssSizeLength)ScrollY); @(UseItemsProvider?$"min-height:{(CssSizeLength)ScrollY};":"") --scrollbar-width: @((CssSizeLength)_scrollBarWidth);">
                                    <table style="@(ScrollX!=null?$"width: {(CssSizeLength)ScrollX}; min-width: 100%;":"") @TableLayoutStyle" @ref="_tableRef">
                                        @colGroup((this, false))
                                        <tbody class="ant-table-tbody">
                                            <tr aria-hidden="true" class="ant-table-measure-row" style="height: 0px; font-size: 0px;">
                                                <CascadingValue Name="IsMeasure" Value="true" IsFixed>
                                                    @ChildContent(_fieldModel)
                                                </CascadingValue>
                                            </tr>
                                            @body(this, _showItems, 0, _rootRowDataCache)
                                        </tbody>
                                        @tfoot(this)
                                    </table>
                                </div>
                            }
                            else if (ScrollX != null)
                            {
                                <div class="ant-table-content" @ref="_tableBodyRef" style="overflow: auto hidden; --scrollbar-width: @((CssSizeLength)_scrollBarWidth);">
                                    <table style="width: @((CssSizeLength)ScrollX); min-width: 100%; @TableLayoutStyle;" @ref="_tableRef">
                                        @colGroup((this, true))
                                        @header(this)
                                        <tbody class="ant-table-tbody">
                                            <tr aria-hidden="true" class="ant-table-measure-row" style="height: 0px; font-size: 0px;">
                                                <CascadingValue Name="IsMeasure" Value="true" IsFixed>
                                                    @ChildContent(_fieldModel)
                                                </CascadingValue>
                                            </tr>
                                            @body(this, _showItems, 0, _rootRowDataCache)
                                        </tbody>
                                        @tfoot(this)
                                    </table>
                                </div>
                            }
                            else
                            {
                                <div class="ant-table-content">
                                    <table style="@TableLayoutStyle;--scrollbar-width: @((CssSizeLength)_scrollBarWidth);" @ref="_tableRef">
                                        @colGroup((this, true))
                                        @header(this)
                                        <tbody class="ant-table-tbody">
                                            @body(this, _showItems, 0, _rootRowDataCache)
                                        </tbody>
                                        @tfoot(this)
                                    </table>
                                </div>
                            }
                        </div>
                        @if (FooterTemplate != null || Footer != null)
                        {
                            <div class="ant-table-footer">
                                @if (FooterTemplate != null)@FooterTemplate else @Footer
                            </div>
                        }
                    </div>
                </CascadingValue>
            </CascadingValue>
        </CascadingValue>
        @if (!HidePagination && PaginationPosition.Contains("bottom"))
        {
            if (PaginationTemplate == null)
            {
                <Pagination Size="@(Size == TableSize.Default ? PaginationSize.Default : PaginationSize.Small)"
                            Class="@_paginationClass.Class"
                            Total="_total"
                            PageSize="PageSize"
                            Current="PageIndex"
                            OnChange="HandlePageChange" />
            }
            else
            {
                @PaginationTemplate((PageSize,PageIndex,_total,_paginationClass.Class, EventCallback.Factory.Create<PaginationEventArgs>(this, HandlePageChange)))
            }
        }
    </Spin>
</div>

@code
{
    RenderFragment<Table<TItem>> header = table =>
  @<Template>
       @{
            var headerRowAttributes = table.OnHeaderRow?.Invoke();
        }
        <thead class="ant-table-thead">
            <CascadingValue Name="IsHeader" Value="true" IsFixed>
                <CascadingValue Value="headerRowAttributes" Name="AntDesign.TableRow.RowAttributes">
                    <CascadingValue Value="table._hasFixRight" Name="AntDesign.TableRow.HasFixRight">
                        <CascadingValue Value="table.ScrollY" Name="AntDesign.TableRow.ScrollY">
                            @if (table.HeaderTemplate != null)
                            {
                                @table.HeaderTemplate(_fieldModel)
                            }
                            else
                            {
                                <TableRow>
                                    @table.ChildContent(_fieldModel)
                                </TableRow>
                            }
                        </CascadingValue>
                    </CascadingValue>
                </CascadingValue>
            </CascadingValue>
        </thead>
    </Template>;

RenderFragment<(Table<TItem> table, bool header)> colGroup = ctx =>
  @<Template>
            @{
        var table = ctx.table;
        var header = ctx.header;
            }
            <colgroup>
                <CascadingValue Name="IsColGroup" Value="true" IsFixed>
                    @table.ChildContent(_fieldModel)
                </CascadingValue>
                @if (table.ScrollY != null && header)
        {
                    <col style="width: @((CssSizeLength)table.ScrollBarWidth); min-width: @((CssSizeLength)table.ScrollBarWidth);" />
        }
            </colgroup>
  </Template>;

 RenderFragment body(Table<TItem> table, IEnumerable<TItem> showItems, int level, IDictionary<TItem, RowData<TItem>> rowDataCache) =>
@<Template>

    @if (table._hasInitialized)
    {
#if NET5_0_OR_GREATER 
            if (table.UseItemsProvider&&!table._isVirtualizeEmpty)
            {
                 <Microsoft.AspNetCore.Components.Web.Virtualization.Virtualize
                    TItem="(TItem,int)"
                    OverscanCount="10"
                    ItemsProvider="table.ItemsProvider"
                    ItemContent="table.bodyRow(table, level, rowDataCache)" >
                        <Placeholder>
                            <tr class="ant-table-row ant-table-row-level-0">
                                @foreach (var item in table.ColumnContext.HeaderColumns)
                                {
                                    <td class="ant-table-cell" colspan="@item.ColSpan">
                                       <Skeleton Active="true" ParagraphRows="1" Paragraph="false" ParagraphWidth="@item.Width"></Skeleton>
                                    </td>
                                }
                            </tr>
                        </Placeholder> 
                    </Microsoft.AspNetCore.Components.Web.Virtualization.Virtualize>
            }
        else
#endif
        if (table._total<=0 || showItems==null)
        {
             <tr class="ant-table-placeholder">
                 <td colspan="@(table.ColumnContext.Columns.Count + (table.ExpandTemplate != null? 1 : 0))" class="ant-table-cell">
                     @if (table.ScrollX != null)
                     {
                        <ResizeObserver RefBack="table.RefBack" OnResize="table.OnResize" />   

                        @if (table._tableWidth>0)
                        {
                            <div class="ant-table-expanded-row-fixed" style="width: @(table._tableWidth)px; position: sticky; left: 0px; overflow: hidden;">
                               @if (table.EmptyTemplate!=null) { @table.EmptyTemplate } else { <Empty Simple /> }
                            </div>
                        }
                     }
                     else
                     {
                          @if (table.EmptyTemplate!=null) { @table.EmptyTemplate } else { <Empty Simple /> }
                     }
                 </td>
             </tr>
        }
#if NET5_0_OR_GREATER
            else if (table.EnableVirtualization) {
                <Microsoft.AspNetCore.Components.Web.Virtualization.Virtualize TItem="ValueTuple<TItem, int>"
                     OverscanCount="10"
                     Items="showItems.Select((data, index) => (data, index)).ToList()"
                     ChildContent="table.bodyRow(table, level, rowDataCache)"/>
            }
#endif
        else
        {
            { @*Build will fail without this block*@ }
            <ForeachLoop TItem="ValueTuple<TItem, int>" 
                    Items="showItems.Select((data, index) => (data, index))"
                     ChildContent="table.bodyRow(table, level, rowDataCache)" />
        }
    }
</Template>;

Func<Table<TItem>, int, IDictionary<TItem, RowData<TItem>>, RenderFragment<(TItem data, int index)>> bodyRow = 
            (table, level, rowDataCache) => tuple =>
@<Template @key="table.RowKey?.Invoke(tuple.data)??tuple">
    @{
        int rowIndex;
        if (level == 0) rowIndex = table.PageSize * (table.PageIndex - 1) + tuple.index + 1;
        else rowIndex = tuple.index + 1;
        var data = tuple.data;
        if (!table._dataSourceCache.TryGetValue(data, out var currentDataItem) || currentDataItem == null)
        {
            currentDataItem = new TableDataItem<TItem>(data, table);
            currentDataItem.SetSelected(table.SelectedRows.Contains(data), triggersSelectedChanged: false);
            table._dataSourceCache.Add(data, currentDataItem);
        }
        if (!rowDataCache.TryGetValue(data, out var currentRowData) || currentRowData == null)
        {
            currentRowData = new RowData<TItem>(currentDataItem)
            {
                Expanded = table.DefaultExpandAllRows && level < table.DefaultExpandMaxLevel
            };
            rowDataCache.Add(data, currentRowData);
        }
        var childrenData = table.TreeChildren(data);
        currentDataItem.HasChildren = childrenData?.Any() == true;
        currentRowData.Level = level;
        currentRowData.RowIndex = rowIndex;
        currentRowData.PageIndex = table.PageIndex;

        <TableRowWrapper RowData="currentRowData">
            @{
                var rowAttributes = table.OnRow?.Invoke(currentRowData);
                if (table.OnRowClick.HasDelegate)
                {
                    rowAttributes ??= new Dictionary<string, object>();
                    rowAttributes.TryAdd("onclick", ((Action)delegate { table.OnRowClick.InvokeAsync(currentRowData); }));
                }

                var rowClassName = table.RowClassName(currentRowData);
                <CascadingValue Value="true" Name="IsBody" IsFixed>
                    <CascadingValue Value="rowAttributes" Name="AntDesign.TableRow.RowAttributes">
                        <CascadingValue Value="rowClassName" Name="AntDesign.TableRow.RowClassName">
                            @if (table.RowTemplate != null)
                            {
                                @table.RowTemplate(currentRowData)
                            }
                            else
                            {
                                <TableRow @key="currentDataItem.Data">
                                    @table.ChildContent(currentDataItem.Data)
                                </TableRow>
                            }
                        </CascadingValue>
                    </CascadingValue>
                </CascadingValue>

                @if (currentDataItem.HasChildren && currentRowData.Expanded)
                {
                    currentRowData.Children ??= new Dictionary<TItem, RowData<TItem>>();
                    @table.body(table, table.SortFilterChildren(childrenData), currentRowData.Level + 1, currentRowData.Children);
                }
                @if (!currentDataItem.HasChildren && table.ExpandTemplate != null && table.RowExpandable(currentRowData) && currentRowData.Expanded)
                {
                    <tr class="ant-table-expanded-row ant-table-expanded-row-level-1 @table.ExpandedRowClassName(currentRowData)"
                        style="@(currentRowData.Expanded?"":"display: none;")">
                        <td colspan="@(table.ColumnContext.Columns.Count+1)" class="ant-table-cell">
                            @table.ExpandTemplate(currentRowData)
                        </td>
                    </tr>
                }
            }
        </TableRowWrapper>
    }
  </Template>;

RenderFragment<Table<TItem>> tfoot = table =>@<Template>
            @if (table._summaryRows?.Any() == true)
    {
                <CascadingValue Value="true" Name="IsSummary" IsFixed>
                    <tfoot class="ant-table-summary">
                        @foreach (var row in table._summaryRows)
                {
                            <tr>
                                @row.ChildContent
                            </tr>
                }
                    </tfoot>
                </CascadingValue>
    }
  </Template>;
}
